package cn.dzhang.spring.boot.monitor;

import java.util.Date;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import cn.dzhang.spring.boot.annotation.SecurityOperation;
import cn.dzhang.spring.boot.model.Device;
import cn.dzhang.spring.boot.model.ModelBase;
import cn.dzhang.spring.boot.model.Resource;
import cn.dzhang.spring.boot.remoting.Authentication;
import cn.dzhang.spring.boot.remoting.AuthenticationContextHolder;

@Aspect
@Component
public class SecurityMonitor {
	private static final Log log = LogFactory.getLog(SecurityMonitor.class);

	@Pointcut("execution(* cn.dzhang.spring.boot.service..*Service.*(..))")
	void serviceMethod() {
	}

	@Pointcut("execution(* cn.dzhang.spring.boot.service..*Service.saveOrUpdate(..))")
	void saveOrUpdateMethod() {
	}

	@Before("saveOrUpdateMethod() && args(model,..)")
	public void setUpdatedDateTime(ModelBase model) {
		model.setUpdatedAt(new Date());
		log.info(model);
	}

	@Before("saveOrUpdateMethod() && args(models,..)")
	public void setUpdatedDateTime(List<? extends ModelBase> models) {
		log.info(models);
		
		for (ModelBase model : models) {
			model.setUpdatedAt(new Date());
		}
	}

	/**
	 * 验证权限
	 *
	 * @param point
	 * @param securityOperation
	 */
	@Before("@annotation(securityOperation) && args(resource,..)")
	public void securityOperation(JoinPoint point,
			SecurityOperation securityOperation, Resource resource) {
		Authentication authentication = getAuthentication();
		log.error(authentication);
	}

	private Authentication getAuthentication() {
		Authentication authentication = AuthenticationContextHolder
				.currentAuthentication();
		return authentication;
	}

	@AfterThrowing(value = "serviceMethod()", throwing = "e")
	public void handleException(Exception e) {
		e.printStackTrace();
		log.error("", e);
	}

	/**
	 * 过滤返回值
	 *
	 * @param result
	 */
	@AfterReturning(pointcut = "serviceMethod()", returning = "result")
	public void filterReturnValue(Object result) {
		if (result instanceof List<?>) {
			List<?> resources = (List<?>) result;

			for (Object resource : resources) {
				if (resource instanceof Device) {
					Device device = (Device) resource;
					log.info(device);
				}
			}
		}
	}
}
